<?php

namespace app\bll;

use core\lib\upload\UploadFile as LibUploadFile;
use Exception;
use hulang\tool\FileHelper;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Melihovv\Base64ImageDecoder\Base64ImageEncoder;
use PhpZip\ZipFile;
use support\Db;
use app\lib\installer\General as LibInstallerGeneral;

class ComponentWidget
{


    /**
     * 获取某个挂件
     *
     * @param integer $id
     * @return array
     */
    public function find(int $id): array
    {
        $data =  Db::table('frame_component_widget')
            ->where('id', '=', $id)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    /**
     * 查询所有挂件
     *
     * @param integer|null $widgettype
     * @return array
     */
    public function select(?int $widgettype = null): array
    {
        return Db::table('frame_component_widget')
            ->when($widgettype !== null, function ($query) use ($widgettype) {
                return $query->where('type', '=', $widgettype);
            })
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }
    /**
     * 根据NAME查询某个挂件
     *
     * @param string $name
     * @return array
     */
    public function findByIdent(string $ident): array
    {

        $data =  Db::table('frame_component_widget')
            ->where('ident', '=', $ident)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }


    /**
     * 根据 挂件名查询
     *
     * @param array $names
     * @return array
     */
    public function selectByIdents(array $idents = []): array
    {
        return Db::table('frame_component_widget')
            ->when($idents, function ($query) use ($idents) {
                return $query->whereIn('ident', $idents);
            })
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }


    public  function install(int $widgettype = 1)
    {


        try {
            $libInstallerGeneral = new LibInstallerGeneral();
            $installres =  $libInstallerGeneral->install(
                $this->getWidgetPath($widgettype),
                ['describe.php']
            );

            //读写配置文件写入数据库
            $describe          = $this->getDescribe($installres['foldername'], $widgettype);
            Db::table('frame_component_widget')
                ->insertGetId($describe);
        } catch (Exception $ex) {
            throw $ex;
        }
    }


    public function onlineUpgrade(int $id)
    {
        $widegt = $this->find($id);

        if (! $widegt) {
            throw new Exception('挂件不存在');
        }

        if (! $widegt['upgrade']) {
            throw new Exception('挂件没有升级地址');
        }
        try {
            $upgrade = $widegt['upgrade'];

            $libInstallerGeneral = new LibInstallerGeneral();
            $res = $libInstallerGeneral->onlineUpgrade(
                $upgrade,
                $widegt['version'],
                $this->getWidgetPath($widegt['type']),
                ['describe.php']
            );

            $describe          = $this->getDescribe($widegt['ident']);
            $describe['nextversion'] = '';
            $describe['version'] = $res['nextVersion'];

            Db::table('frame_component_widget')
                ->where('id', '=', $id)
                ->update($describe);
        } catch (Exception $ex) {

            throw $ex;
        }
    }


    /**
     * 手动升级
     *
     * @return void
     */
    public function handleUpgrade(int $id)
    {
        try {
            $wigdet              = $this->find($id);
            $libInstallerGeneral = new LibInstallerGeneral();
            $res                 = $libInstallerGeneral->offlineUpgrade(
                $wigdet['ident'],
                $wigdet['version'],
                $this->getWidgetPath($wigdet['type']),
                ['describe.php']
            );

            //读写配置文件写入数据库
            $describe          = $this->getDescribe($wigdet['ident'], $wigdet['type']);
            $describe['nextversion'] = '';
            $describe['version'] = $res['nextVersion'];

            Db::table('frame_component_widget')
                ->where('id', '=', $id)
                ->update($describe);
        } catch (Exception $ex) {
            throw $ex;
        }
    }


    /**
     * 卸载
     *
     * @param integer $id
     * @return void
     */
    public function uninstall(int $id)
    {

        Db::beginTransaction();
        try {
            $widget = $this->find($id);
            Db::table('frame_component_widget')
                ->where('id', '=', $id)
                ->delete();

            Db::table('frame_user_widget')
                ->where('widget', '=', $widget['ident'])
                ->delete(); //删除用户挂件配置

            Db::table('frame_site_role_widget')
                ->where('ident', '=', $widget['ident'])
                ->delete(); //删除角色挂件配置

            //文件夹删除
            $dir = $this->getWidgetPath($widget['type']) .
                '/' . $widget['ident'] . '/';

            if (file_exists($dir)) {
                FileHelper::delDir($dir);
            }
            Db::commit();
        } catch (Exception $ex) {
            Db::rollBack();
            throw $ex;
        }
    }



    public function getWidgetPath(int $widgettype = 1)
    {
        switch ($widgettype) {
            case 1:
                return base_path() . '/component/widget/admin/';
                break;
            case 2:
                return base_path() . '/component/widget/uc/';
                break;
        }
    }


    /**
     * 获取插件的配置文件
     *
     * @param string $path
     * @return array
     */
    public function getDescribe(string $foldername, int $widgettype = 1): array
    {
        $describe          = include $this->getWidgetPath($widgettype) . $foldername . '/describe.php';
        $describe['ident'] = $foldername;
        //logo base64
        $logo = $this->getWidgetPath($widgettype) . $foldername  . '/logo.png';
        if (file_exists($logo)) {
            $imageEncoder = Base64ImageEncoder::fromFileName(
                $logo,
                ['jpeg', 'png', 'gif']
            );

            $describe['logo'] = $imageEncoder->getDataUri();
        }
        return $describe;
    }


    /**
     * 检查更新
     *
     * @param integer|array $widget_or_id
     * @return boolean
     */
    public function checkUpgrade(int|array $widget_or_id): bool
    {
        $widget = $widget_or_id;
        if (is_int($widget_or_id)) {
            $widget = $this->find($widget_or_id);
        }
        $upgrade = $widget['upgrade'];
        if ($upgrade == '') {
            return false;
        }
        $libInstallerGeneral = new LibInstallerGeneral();
        $nextVersion = $libInstallerGeneral->getNextUpgradeVersion($upgrade, $widget['version']);
        if ($nextVersion) {
            Db::table('frame_component_widget')
                ->where('id', '=', $widget['id'])
                ->update([
                    'nextversion' => $nextVersion['nextVersion']
                ]);
            return true;
        }
        Db::table('frame_component_widget')
            ->where('id', '=', $widget['id'])
            ->update([
                'nextversion' => ''
            ]);
        return false;
    }

    /**
     * 检查所有元素是否有版本更新
     *
     * @return void
     */
    public function checkAllUpgrade()
    {
        $elements = $this->select();
        foreach ($elements as $element) {
            $this->checkUpgrade($element);
        }
    }



    /**
     * 分页查询
     *
     * @param string $ident 标识
     * @param string $title 名称
     * @param integer $type 类型
     * @param integer $pagesize
     * @return LengthAwarePaginator
     */
    public function paginator(
        string $ident = '',
        string $title = '',
        ?int $type = null,
        int $pagesize = 20
    ): LengthAwarePaginator {
        return  Db::table('frame_component_widget')
            ->when($ident != '', function ($query) use ($ident) {
                return $query->where('ident', 'like', '%' . $ident . '%');
            })
            ->when($title != '', function ($query) use ($title) {
                return $query->where('title', 'like', '%' . $title . '%');
            })
            ->when($type !== null, function ($query) use ($type) {
                return $query->where('type', '=', $type);
            })
            ->orderBy('id', 'desc')
            ->paginate($pagesize);
    }
}
